package system.service.sys.impl;

import framework.config.SecurityConfig;
import framework.utils.VariableUtil;
import framework.utils.VersionUtil;
import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import system.entity.SysConfig;
import system.mapper.SysConfigMapper;
import system.service.sys.SysConfigService;
import system.vo.ConfigUI;
import system.vo.ConfigVO;

import java.util.List;
import java.util.UUID;

@Slf4j
@Service
public class SysConfigServiceImpl implements SysConfigService {
    private final static String CAHCE_NAME = "config";
    private final static String VERSION_KEY = "cv";

    @Autowired
    @Getter
    private SysConfigMapper mapper;
    @Autowired
    private CacheManager cacheManager;
    @Autowired
    private SecurityConfig securityConfig;

    /**
     * 获取配置版本号
     *
     * @return
     */
    @Override
    public String getConfigVersion() {
        Cache cache = cacheManager.getCache(CAHCE_NAME);
        String s = cache.get(VERSION_KEY, String.class);
        if (s == null) {
            s = UUID.randomUUID().toString().replace("-", "");
            cache.put(VERSION_KEY, s);
        }
        return s;
    }

    /**
     * 更新配置版本号
     */
    @Override
    public void updateConfigVersion() {
        Cache cache = cacheManager.getCache(CAHCE_NAME);
        cache.evict(VERSION_KEY);
    }

    /**
     * 获取具有版本控制的配置项
     *
     * @param key
     * @param cls
     * @param <T>
     * @return
     */
    @Override
    public <T> T getConfigOfVersion(String key, Class<T> cls) {
        String version = this.getConfigVersion();
        String cacheKey = key + "_" + version;
        //
        Cache cache = cacheManager.getCache(CAHCE_NAME);
        T t = cache.get(cacheKey, cls);
        return t;
    }

    /**
     * 设置具有版本控制的配置项
     *
     * @param key
     * @param obj
     * @return
     */
    @Override
    public void setConfigOfVersion(String key, Object obj) {
        String version = this.getConfigVersion();
        String cacheKey = key + "_" + version;
        //
        Cache cache = cacheManager.getCache(CAHCE_NAME);
        cache.put(cacheKey, obj);
    }


    @Override
    public ConfigVO config() {

        ConfigVO vo = this.getConfigOfVersion("config", ConfigVO.class);
        if (vo != null) {
            //缓存命中
            return vo;
        }

        //加载配置
        List<SysConfig> configList = mapper.list(new SysConfig());
        vo = new ConfigVO();
        BeanWrapperImpl beanWrapper = new BeanWrapperImpl(vo);
        for (SysConfig item : configList) {
            String nameHump = VariableUtil.underlineToCamel(item.getId());
            try {
                if (beanWrapper.isWritableProperty(nameHump)) {
                    beanWrapper.setPropertyValue(nameHump, item.getV());
                }
            } catch (Exception exception) {
                log.error("Not allow access config \"" + nameHump + "\"", exception);
            }
        }

        //
        this.setConfigOfVersion("config", vo);

        //
        return vo;
    }

    @Override
    public Integer add(SysConfig param) {
        int rows = SysConfigService.super.add(param);
        //更新版本控制
        this.updateConfigVersion();
        return rows;
    }

    @Override
    public Integer deleteById(String id) {
        int rows = SysConfigService.super.deleteById(id);
        //更新版本控制
        this.updateConfigVersion();
        return rows;
    }

    @Override
    public Integer update(SysConfig param) {
        int rows = mapper.update(param);
        //更新版本控制
        this.updateConfigVersion();
        return rows;
    }

    /**
     * 获取UI可用配置项
     *
     * @return
     */
    @SneakyThrows
    @Override
    public ConfigUI getUI() {
        ConfigVO config = config();
        //
        ConfigUI ui = new ConfigUI();
        BeanUtils.copyProperties(config, ui);
        //
        ui.setBuildVersion(VersionUtil.jarVersionString(this.getClass()));
        //
        ui.setLoginCaptchaEnable(securityConfig.getEnableLoginCaptcha() ? 1 : 0);
        //
        return ui;
    }

}